import { createElement } from "./createElement"
import { patchVnode } from "./patchVNode"

/**
 * diff 算法
 */
export function updateChildren(parent, oldCh, newCh) {
    // 初始化四个指针
    let [
        newStartIndex, newEndIndex,
        oldStartIndex, oldEndIndex
    ] = [
            0, newCh.length - 1,
            0, oldCh.length - 1
        ]
    // 初始化四个节点
    let [
        newStartNode, newEndNode,
        oldStartNode, oldEndNode
    ] = [
            newCh[newStartIndex], newCh[newEndIndex],
            oldCh[oldStartIndex], oldCh[oldEndIndex]
        ]
    let oldRemainder = {}
    function handleUndefined() {
        const bl = oldStartNode === undefined
            || oldEndNode === undefined
            || newStartNode === undefined
            || newEndNode === undefined

        if (oldStartNode === undefined) {
            oldStartNode = oldCh[++oldStartIndex]
        } else if (oldEndNode === undefined) {
            oldEndNode = oldCh[--oldEndIndex]
        } else if (newStartNode === undefined) {
            newStartNode = newCh[++newStartIndex]
        } else if (newEndNode === undefined) {
            newEndNode = newCh[--newEndIndex]
        }
        return bl
    }
    while (newStartIndex <= newEndIndex && oldStartIndex <= oldEndIndex) {
        // 忽略 else 中置空的 
        if (handleUndefined()) {
            continue
        }
        // 四个指针判断
        if (checkSameNode(newStartNode, oldStartNode)) {
            // 新前和旧前匹配，更新内容，移动指针
            patchVnode(oldStartNode, newStartNode)
            newStartNode = newCh[++newStartIndex]
            oldStartNode = oldCh[++oldStartIndex]
            console.log('新前/旧前', newStartNode.text)
        } else if (checkSameNode(newEndNode, oldEndNode)) {
            // 新后和旧后匹配，更新内容，移动指针
            patchVnode(oldEndNode, newEndNode)
            oldEndNode = oldCh[--oldEndIndex]
            newEndNode = newCh[--newEndIndex]
            console.log('新后/旧后', newEndNode.text)
        } else if (checkSameNode(newEndNode, oldStartNode)) {
            // 新后和旧前匹配，更新内容，移动旧前到旧后之后，移动指针
            patchVnode(oldStartNode, newEndNode)
            console.log(oldEndNode.elm.nextSibling)
            parent.insertBefore(oldStartNode.elm, oldEndNode.elm.nextSibling)
            newEndNode = newCh[--newEndIndex]
            oldStartNode = oldCh[++oldStartIndex]
            console.log('新后/旧前', newEndNode.text)
        } else if (checkSameNode(newStartNode, oldEndNode)) {
            // 新前和旧后匹配，更新内容，移动旧后到旧前之前，移动指针
            patchVnode(oldEndNode, newStartNode)
            parent.insertBefore(oldEndNode.elm, oldStartNode.elm)
            newStartNode = newCh[++newStartIndex]
            oldEndNode = oldCh[--oldEndIndex]
            console.log('新前/旧后', newStartNode.text)
        } else {
            // 此时需要判断新前是不是新节点，使用缓存机制
            if (Object.keys(oldRemainder).length === 0) {
                for (let i = oldStartIndex; i <= oldEndIndex; i++) {
                    oldRemainder[oldCh[i].key] = i
                }
            }
            const index = oldRemainder[newStartNode.key]
            if (index) {
                // 旧节点
                const oldNode = oldCh[index]
                patchVnode(oldNode, newStartNode)
                parent.insertBefore(oldNode.elm, oldStartNode.elm)
                // 处理完的置空，防止循环后再处理
                oldCh[index] = undefined
            } else {
                // 新节点
                parent.insertBefore(createElement(newStartNode), oldStartNode.elm)
            }
            newStartNode = newCh[++newStartIndex]
        }
    }
    if (newStartIndex <= newEndIndex || oldStartIndex <= oldEndIndex) {
        if (oldStartIndex > oldEndIndex) {
            // 插入新前和新后之间的节点，到旧前之前
            console.log(oldCh[oldStartIndex], oldStartNode)
            for (let i = newStartIndex; i <= newEndIndex; i++) {
                parent.insertBefore(createElement(newCh[i]), oldStartNode.elm)
            }
        } else {
            // 删除旧前和旧后之间的节点
            for (let i = oldStartIndex; i <= oldEndIndex; i++) {
                parent.removeChild(oldCh[i].elm)
            }
        }
    }
}

function checkSameNode(node1, node2) {
    return node1.sel === node2.sel && node1.key === node2.key
}